package cn.iocoder.yudao.module.promotion.groupon.service.app;

import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.business.basic.dao.query.CoreQueryWrapper;
import cn.iocoder.yudao.framework.business.basic.enums.SortTypeEnum;
import cn.iocoder.yudao.framework.business.basic.pojo.dto.LocationQueryDTO;
import cn.iocoder.yudao.framework.business.basic.pojo.dto.SortQueryDTO;
import cn.iocoder.yudao.framework.business.basic.service.impl.BaseService;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.api.infrastructure.config.ConfigApiV2;
import cn.iocoder.yudao.module.api.promotion.gift.dto.GiftActivityVO;
import cn.iocoder.yudao.module.api.promotion.groupon.dto.GrouponPackageRespDTO;
import cn.iocoder.yudao.module.promotion.gift.service.app.AppGiftActivityService;
import cn.iocoder.yudao.module.promotion.groupon.dao.GrouponPackageMapper;
import cn.iocoder.yudao.module.promotion.groupon.pojo.bo.ShopIdDistanceBO;
import cn.iocoder.yudao.module.promotion.groupon.pojo.bo.ShopIdPackageBO;
import cn.iocoder.yudao.module.promotion.groupon.pojo.dto.AppGrouponPackageQueryDTO;
import cn.iocoder.yudao.module.promotion.groupon.pojo.po.GrouponPackage;
import cn.iocoder.yudao.module.promotion.groupon.pojo.vo.AppGrouponPackageVO;
import cn.iocoder.yudao.module.promotion.groupon.pojo.vo.AppGrouponProductRespVO;
import jakarta.annotation.Nonnull;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import java.util.*;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;

/**
 * <pre>
 * OOoO0OOoO0OOOooo0oOOOO0OOOOO0oooOO0ooOOO0Ooooo0OOOOo0ooooO0OOooo0Ooooo0OOOOO
 *  这里是文件说明
 * OOoO0OOoO0OOOooo0oOOOO0OOOOO0oooOO0ooOOO0Ooooo0OOOOo0ooooO0OOooo0Ooooo0OOOOO
 * </pre>
 *
 * @author 山野羡民（1032694760@qq.com）
 * @since 2025/01/13
 */
@Service
@Validated
public class AppGrouponPackageServiceImpl extends BaseService<GrouponPackage, AppGrouponPackageVO, AppGrouponPackageQueryDTO> implements AppGrouponPackageService {
    @Resource
    private GrouponPackageMapper grouponPackageMapper;

    @Resource
    @Lazy // 延迟加载，避免循环依赖
    private AppGrouponProductService appGrouponProductService;
    @Resource
    @Lazy // 延迟加载，避免循环依赖
    private AppGiftActivityService appGiftActivityService;

    @Resource
    private ConfigApiV2 configApiV2;

    @Override
    protected GrouponPackageMapper getInjectedMapper() {
        return grouponPackageMapper;
    }

    @Nonnull
    @Override
    protected CoreQueryWrapper<GrouponPackage> buildQueryWrapper(AppGrouponPackageQueryDTO param) {
        CoreQueryWrapper<GrouponPackage> wrapper = super.buildQueryWrapper(param);
        wrapper.eqIfPresent("shop_id", param.getShopId());
        wrapper.inIfPresent("shop_id", param.getShopIds());
        wrapper.leIfPresent("min_people", param.getPeople());
        wrapper.geIfPresent("max_people", param.getPeople());
        wrapper.eq("enabled", true);
        wrapper.orderByDesc("shop_id");
        wrapper.orderByAsc("price");
        wrapper.orderByDesc("id");
        return wrapper;
    }

    @Override
    public AppGrouponPackageVO getDetail(Long id) {
        AppGrouponPackageVO respVO = super.getDetail(id);
        List<Long> giftActivityIds = respVO.getGiftActivityIds();
        if (CollUtil.isNotEmpty(giftActivityIds)) {
            respVO.setGiftActivities(appGiftActivityService.getList(giftActivityIds));
        }
        List<AppGrouponProductRespVO> products = appGrouponProductService.getListByPackageId(id);
        respVO.setProducts(products);
        respVO.setDeductUnitPrice(configApiV2);
        return respVO;
    }

    @Override
    public List<AppGrouponPackageVO> getList(@Nonnull AppGrouponPackageQueryDTO param) {
        List<AppGrouponPackageVO> data = super.getList(param);
        Set<Long> giftActivityIds = data.stream().map(AppGrouponPackageVO::getGiftActivityIds)
                .filter(Objects::nonNull).flatMap(List::stream).collect(Collectors.toSet());
        Map<Long, GiftActivityVO> giftActivityMap = appGiftActivityService.getMap(giftActivityIds, GiftActivityVO::getId);
        Set<Long> packageIds = data.stream().map(AppGrouponPackageVO::getId).collect(Collectors.toSet());
        Map<Long, List<AppGrouponProductRespVO>> productMap = appGrouponProductService.getMapByPackageIds(packageIds);
        for (AppGrouponPackageVO item : data) {
            List<Long> list = item.getGiftActivityIds();
            if (CollUtil.isNotEmpty(list)) {
                item.setGiftActivities(list.stream().map(giftActivityMap::get).collect(Collectors.toList()));
            }
            item.setProducts(productMap.getOrDefault(item.getId(), new ArrayList<>()));
            item.setDeductUnitPrice(configApiV2);
        }
        return data;
    }

    @Override
    public Map<Long, List<GrouponPackageRespDTO>> getMapByShopIds(Collection<Long> shopIds, int limit) {
        Map<Long, List<GrouponPackageRespDTO>> map = new HashMap<>();
        if (CollUtil.isEmpty(shopIds)) {
            return map;
        }
        for (Long shopId : shopIds) {
            map.put(shopId, new ArrayList<>());
        }
        List<GrouponPackage> dos = grouponPackageMapper.selectSimpleListByShopIds(shopIds, limit);
        if (CollUtil.isEmpty(dos)) {
            return map;
        }
        for (GrouponPackage aDo : dos) {
            List<GrouponPackageRespDTO> tmp = map.computeIfAbsent(aDo.getShopId(), k -> new ArrayList<>());
            GrouponPackageRespDTO dto = BeanUtils.toBean(aDo, GrouponPackageRespDTO.class);
            dto.setDeductUnitPrice(configApiV2);
            tmp.add(dto);
        }
        return map;
    }

    @Override
    public Map<Long, Integer> getShopDistanceMap(LocationQueryDTO location, SortQueryDTO sort) {
        if (sort == null) {
            sort = new SortQueryDTO();
        }
        SortTypeEnum sortTypeEnum = SortTypeEnum.codeOf(sort.getSortType());
        if (location == null || location.getLatitude() == null || location.getLongitude() == null
            || (location.getLatitude() == 0D && location.getLongitude() == 0D)) {
            List<Long> list;
            if (SortTypeEnum.RANDOM.equals(sortTypeEnum)) {
                list = grouponPackageMapper.selectShopIdsOrderByRandom();
            } else if (SortTypeEnum.SCORE.equals(sortTypeEnum)) {
                list = grouponPackageMapper.selectShopIdsOrderByScore();
            } else if (SortTypeEnum.PRICE.equals(sortTypeEnum)) {
                list = grouponPackageMapper.selectShopIdsOrderByPrice();
            } else {
                list = grouponPackageMapper.selectShopIdsOrderById();
            }
            Map<Long, Integer> map = new HashMap<>();
            if (CollUtil.isEmpty(list)) {
                return map;
            }
            for (Long shopId : list) {
                map.put(shopId, -1);
            }
            return map;
        }
        List<ShopIdDistanceBO> list = grouponPackageMapper.selectShopIdsAndDistance(location.getLongitude(), location.getLatitude());
        if (CollUtil.isEmpty(list)) {
            return new HashMap<>();
        }
        return convertMap(list, ShopIdDistanceBO::getShopId, ShopIdDistanceBO::getDistanceKm);
    }

    @Override
    public Map<Long, Long> getShopPackageMap(Collection<Long> shopIds) {
        List<ShopIdPackageBO> list = grouponPackageMapper.selectByShopIds(shopIds);
        if (CollUtil.isEmpty(list)) {
            return new HashMap<>();
        }
        return convertMap(list, ShopIdPackageBO::getShopId, ShopIdPackageBO::getPackageId);
    }

    @Override
    public PageResult<AppGrouponPackageVO> getPage(Integer pageNo, Integer pageSize, @Nonnull AppGrouponPackageQueryDTO param) {
        PageResult<GrouponPackage> page = grouponPackageMapper.selectPage(pageNo, pageSize, buildQueryWrapper(param));
        List<AppGrouponPackageVO> list = page.getList().stream().map(this::convertToViewObject).toList();
        list.forEach(it -> it.setDeductUnitPrice(configApiV2));
        return new PageResult<>(list, page.getTotal());
    }

}
